from playwright.sync_api import Page, Locator, expect


class PageSlicer:
    def __init__(self, page: Page, debug_tag: str) -> None:
        self.slicer_box = page.locator(
            f'css=[data-debug-tag="{debug_tag}"][data-cp-tag="qsSlicer"]'
        )
        self.select_locator = self.slicer_box.get_by_text("arrow_drop_down")
        self.page = page
        self.options_pane = self.page.locator("css=body > div > .q-menu")

    def switch_options_pane(self):
        """eq by click"""
        self.select_locator.click()
        self.page.wait_for_timeout(500)

    def select_options_by_text(self, text: str):
        self.options_pane.get_by_role("option", name=text).click()

    def clear_selected(self):
        self.slicer_box.get_by_role("button", name="cancel").click()

    def get_option_values(self):
        return self.options_pane.locator(
            "css= .q-virtual-scroll__content > div"
        ).all_text_contents()


class PageCheckbox:
    def __init__(self, page: Page, debug_tag: str) -> None:
        self._checkbox_div = page.locator(
            f'css=[data-debug-tag="{debug_tag}"][data-cp-tag="Checkbox"]'
        )
        self._labels_box = self._checkbox_div.locator("css= .labels-box")
        self._reset_button = self._checkbox_div.locator(
            "css= .funs-buttons .reset-filter"
        )
        self._deselect_button = self._checkbox_div.locator(
            "css= .funs-buttons .de-selected"
        )

        self._allselect_button = self._checkbox_div.locator(
            "css= .funs-buttons .all-selected"
        )
        self.page = page

    def click_by_text(self, text: str):
        self._labels_box.locator("css = .pybi-checkbox_content").filter(
            has_text=text
        ).click()

    def get_option_values(self):
        return self._labels_box.locator(
            "css = .pybi-checkbox_content > span"
        ).all_text_contents()

    def click_reset(self):
        self._reset_button.dispatch_event("mouseover")
        self._reset_button.click()

    def click_deselect(self):
        self._deselect_button.dispatch_event("mouseover")
        self._deselect_button.click()

    def click__all_select(self):
        self._allselect_button.dispatch_event("mouseover")
        self._allselect_button.click()


class PageText:
    def __init__(self, page: Page, debug_tag: str) -> None:
        self.text_box = page.locator(f'css=[data-debug-tag="{debug_tag}"]')
        self.page = page

    def get_text(self):
        return self.text_box.inner_text()
        # return self.options_pane.get_by_role("listitem").all_text_contents()


class PageTable:
    def __init__(self, page: Page, debug_tag: str) -> None:
        self.table = page.locator(f'css=[data-debug-tag="{debug_tag}"]')

    def get_header_cells(self):
        cells = self.table.locator("css=.q-table > thead").get_by_role("cell")
        return cells

    def get_rows(
        self,
    ):
        rows = self.table.locator("css=.q-table > tbody").get_by_role("row")
        return rows

    def get_row_values(self, row_idx: int):
        return self.get_rows().all()[row_idx].get_by_role("cell").all_text_contents()

    def get_table_col_values(self, col_idx: int):
        return list(cell.text_content() for cell in self._get_table_col(col_idx))

    def _get_table_col(self, col_idx: int):
        rows = self.get_rows()
        for row in rows.all():
            yield row.get_by_role("cell").all()[col_idx]

    def get_footer_rows(self):
        rows = self.table.locator("css=.el-table__footer-wrapper").get_by_role("row")
        return rows

    def get_footer_row_values(self, row_idx: int):
        return (
            self.get_footer_rows()
            .all()[row_idx]
            .get_by_role("cell")
            .all_text_contents()
        )

    def click_copy_data_button(self):
        self.table.get_by_role("button", name="copy").click()


class PageTabs:
    def __init__(self, page: Page, debug_tag: str) -> None:
        self.cp_box = page.locator(
            f'css=[data-debug-tag="{debug_tag}"][data-cp-tag="qsTabs"]'
        )
        self.header_box = self.cp_box.locator("css=.q-tabs")
        self.page = page
        self.body_box = (
            self.cp_box.locator("css=.q-tab-panels").get_by_role("tabpanel").nth(1)
        )

    def activate_tab(self, tab_name: str):
        target = self.header_box.get_by_role("tab", name=tab_name)
        target.click()
        self.page.wait_for_timeout(500)

    def get_body_text(self):
        return self.body_box.inner_text()

    def get_body_texts_list(self):
        return self.body_box.all_inner_texts()


class PageEChart:
    def __init__(self, page: Page, debug_tag: str) -> None:
        self.chart_box = page.locator(
            f'css=[data-debug-tag="{debug_tag}"][data-cp-tag="EChart"]'
        )
        self.chartIns_box = self.chart_box.locator(f"css= > .echart")
        self.page = page

    def get_locator_by_text(self, text: str):
        return self.chart_box.locator("css=text").filter(has_text=text)

    def should_has_text(self, text: str):
        self.get_locator_by_text(text).wait_for(timeout=2000)

    def should_not_has_text(self, text: str):
        self.get_locator_by_text(text).wait_for(timeout=1000, state="detached")

    def scroll2show(self):
        self.chart_box.scroll_into_view_if_needed()
        return self

    def hover_series(
        self, x_value, y_value, color=None, seriesIndex=0, offset_x=0, offset_y=0
    ):
        x, y = cal_series_pos(self.chartIns_box, x_value, y_value, color, seriesIndex)

        self.page.mouse.move(
            x + offset_x,
            y + offset_y,
        )

    def click_series(self, x_value, y_value, color=None, seriesIndex=0):
        x, y = cal_series_pos(self.chartIns_box, x_value, y_value, color, seriesIndex)

        self.page.mouse.click(
            x,
            y,
        )

    def get_options(self):
        opts = self.chartIns_box.evaluate(
            f"node => echarts.getInstanceByDom(node).getOption()"
        )
        return opts

    def has_scrollbar(self):
        return self.chart_box.evaluate("node => node.scrollHeight > node.clientHeight")

    def click_back_to_button(self):
        self.chart_box.get_by_text("上一级").click()


class PageInput:
    def __init__(self, page: Page, debug_tag: str) -> None:
        self.box = page.locator(
            f'css=[data-debug-tag="{debug_tag}"][data-cp-tag="qsInput"]'
        )
        self.input_tag = self.box.get_by_role("textbox")
        self.page = page

    def input(self, value: str):
        self.input_tag.fill(value)
        return self

    def clear(self):
        self.input("")
        return self


class PageNumberSlider:
    def __init__(self, page: Page, debug_tag: str) -> None:
        self.box = page.locator(
            f'css=[data-debug-tag="{debug_tag}"][data-cp-tag="elNumberSlider"]'
        )
        self.page = page

    def drag_start_point(self, arrow="ArrowRight"):
        target = self.box.locator(
            'css=div.el-slider__button-wrapper[aria-label="pick start value"]'
        )
        target.click()
        target.press(arrow)
        return self

    def drag_end_point(self, arrow="ArrowLeft"):
        target = self.box.locator(
            'css=div.el-slider__button-wrapper[aria-label="pick end value"]'
        )
        target.click()
        target.press(arrow)
        return self


class PageMermaid:
    def __init__(self, page: Page, debug_tag: str) -> None:
        self.box = page.locator(
            f'css=[data-debug-tag="{debug_tag}"][data-cp-tag="Mermaid"]'
        )
        self.page = page

    def get_text(self):
        return self.box.inner_text()
        # return self.options_pane.get_by_role("listitem").all_text_contents()

    def click(self, content: str):
        return self.box.get_by_text(content).click()

    def should_contain(self, content: str):
        expect(self.box.get_by_alt_text(content))

    def hover(self):
        self.box.hover()


class PageSizebar:
    def __init__(self, page: Page) -> None:
        self.sizebar_box = page.locator(f'css=[data-cp-tag="elSizebar"]')

        self.page = page
        self.open_button = self.page.locator("css=.pybi-sizebar_land-mark")

    def open(self):
        self.open_button.click()

    def close(self):
        box = self.sizebar_box.locator("css = .el-drawer")
        rect = box.evaluate("node => node.getBoundingClientRect()")
        x = rect["x"] - 50
        y = rect["y"] + 50
        self.page.mouse.click(x, y)


def cal_series_pos(chartIns_box: Locator, x_value, y_value, color=None, seriesIndex=0):
    finder = ""
    if color is None:
        finder = f"{{ seriesIndex: {seriesIndex} }}"
    else:
        finder = f"{{ seriesName: {tran_str(color)} }}"

    pos_x, pos_y = chartIns_box.evaluate(
        f"node => echarts.getInstanceByDom(node).convertToPixel({finder}, [{tran_str(x_value)}, {tran_str(y_value)}])"
    )

    box = chartIns_box.bounding_box()
    return (
        box["x"] + pos_x,
        box["y"] + pos_y,
    )


def tran_str(value):
    if isinstance(value, str):
        return f"'{value}'"
    return value


def err_count(page: Page):
    return page.locator("css=.err").count()


class PageMarkdown:
    def __init__(self, page: Page, debug_tag: str) -> None:
        self.box = page.locator(
            f'css=[data-debug-tag="{debug_tag}"][data-cp-tag="Markdown"]'
        )
        self.page = page


class PageButton:
    def __init__(self, page: Page, debug_tag: str) -> None:
        self.box = page.locator(f'css=[data-debug-tag="{debug_tag}"]')
        self.page = page

    def click(self):
        self.box.click()
